package cn.cyan;

import cn.hutool.core.text.StrFormatter;
import com.google.common.collect.Lists;
import lombok.Data;

import java.time.LocalDate;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

public class HolidayCalculator {

    public static void main(String[] args) {
        HolidayCalculator calculator = new HolidayCalculator();
        Map<Integer, List<Holiday>> holidays = calculator.holidays();
        int maxYear = holidays.keySet().stream().max(Integer::compareTo).get();

        LocalDate date = LocalDate.now();
        while (true) {
            Info info = calculator.calculate(date, holidays);
            System.out.println(info.info());
            date = date.plusDays(1);
            if (date.getYear() > maxYear) {
                break;
            }
        }
    }


    private Map<Integer, List<Holiday>> holidays() {
        Map<Integer, List<Holiday>> holidays = new HashMap<>();
        holidays.put(2024, Lists.newArrayList(
                new Holiday("元旦", "2024-01-01"),
                new Holiday("春节", "2024-02-10", "2024-02-17", Lists.newArrayList("2024-02-04", "2024-02-18")),
                new Holiday("清明节", "2024-04-04", "2024-04-06", Lists.newArrayList("2024-04-07")),
                new Holiday("劳动节", "2024-05-01", "2024-05-05", Lists.newArrayList("2024-04-28", "2024-05-11")),
                new Holiday("端午节", "2024-06-10"),
                new Holiday("中秋节", "2024-09-15", "2024-09-17", Lists.newArrayList("2024-09-14")),
                new Holiday("国庆节", "2024-10-01", "2024-10-07", Lists.newArrayList("2024-09-29", "2024-10-12"))
        ));
        return holidays;
    }

    public Info calculate(LocalDate date, Map<Integer, List<Holiday>> holidays) {
        return this.calculate(date, holidays.getOrDefault(date.getYear(), new ArrayList<>()));
    }

    public Info calculate(LocalDate date, List<Holiday> holidays) {
        for (Holiday holiday : holidays) {
            if (!date.isBefore(holiday.getStart()) && !date.isAfter(holiday.getEnd())) {
                return new Info(date, Type.HOLIDAY, holiday.getName());
            }
            for (LocalDate overtime : holiday.getOvertime()) {
                if (date.isEqual(overtime)) {
                    return new Info(date, Type.OVERTIME, holiday.getName() + "-调休");
                }
            }
        }

        if (date.getDayOfWeek().getValue() <= 5) {
            return new Info(date, Type.WORKDAY);
        } else {
            return new Info(date, Type.WEEKEND);
        }
    }


    /**
     * 类型
     *
     * @author Neo
     * @since 2023/12/25 10:23
     */
    public enum Type {
        /**
         * 工作日
         */
        WORKDAY,
        /**
         * 周末
         */
        WEEKEND,
        /**
         * 节假日
         */
        HOLIDAY,
        /**
         * 调休
         */
        OVERTIME;

        /**
         * 是否工作日
         *
         * @author Neo
         * @since 2023/12/25 10:06
         */
        public static boolean isWorkday(Type type) {
            return WORKDAY == type || OVERTIME == type;
        }

    }


    @Data
    public static class Holiday {
        private String name;

        private LocalDate start;

        private LocalDate end;

        private List<LocalDate> overtime;


        public Holiday(String name, String start) {
            this.name = name;
            this.start = LocalDate.parse(start);
            this.end = LocalDate.parse(start);
            this.overtime = Collections.emptyList();
        }

        public Holiday(String name, String start, String end) {
            this.name = name;
            this.start = LocalDate.parse(start);
            this.end = LocalDate.parse(end);
            this.overtime = Collections.emptyList();
        }

        public Holiday(String name, String start, String end, List<String> overtime) {
            this.name = name;
            this.start = LocalDate.parse(start);
            this.end = LocalDate.parse(end);
            this.overtime = overtime.stream().map(LocalDate::parse).collect(Collectors.toList());
        }
    }


    @Data
    public static class Info {
        private LocalDate date;
        private Type type;
        private boolean workday;
        private String remark;

        public Info(LocalDate date, Type type) {
            this.date = date;
            this.type = type;
            this.workday = Type.isWorkday(type);
            this.remark = date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINA);
        }

        public Info(LocalDate date, Type type, String remark) {
            this.date = date;
            this.type = type;
            this.workday = Type.isWorkday(type);
            this.remark = remark;
        }

        public String info() {
            return StrFormatter.format("{} \t {} \t {} \t {}", date, workday ? "上班" : "放假", type, remark);
        }
    }
}
